﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.UI.Xaml.Media;

using Coder.Framework;

namespace Coder.ViewModel
{
    public class ChallengeViewModel : Bindable
    {
        private readonly string _challengeURL = "http://www.bytecode.ca/coder/challenges.txt";

        List<Challenge> _challengeList;
        //The Challenge List Binded to the MainPage.
        public List<Challenge> ChallengeList
        {
            get { return _challengeList; }
            set { _challengeList = value; PropertyChangedEvent("ChallengeList"); }
        }

        List<Challenge> _miniChallengeList;
        /// <summary>
        /// Represents a minified version of the complete challenge list. The items presented are random.
        /// </summary>
        public List<Challenge> MiniChallengeList
        {
            get { return _miniChallengeList; }
            set { _miniChallengeList = value; PropertyChangedEvent("MiniChallengeList"); }
        }

        public ChallengeViewModel()
        {
            ChallengeList = new List<Challenge>();
        }

        /// <summary>
        /// Retrieves all challenges hosted on Byte Code Canada.
        /// Rules:
        /// 1. No Two Titles may be the same. This is how to check if a challenge is already saved!
        /// 2. The end of the challenges.txt must end with a number! This is so that off-by-one does not occur.
        /// Format of a Txt Challenge in the server file:
        /// 
        /// 1 - The ID of the challenge.
        /// T:Factorial Challenge - The Title of the Challenge
        /// D:Factorials are.... - The Description of the Challenge.
        /// R:1 - The Difficulty Rating of the Challenge.
        /// SI:5 - Sample Input
        /// SO:120 - Sample Output
        /// I:7 - Test Input
        /// O:5040 - Test Output
        /// 
        /// </summary>
        /// <param name="savedChallenges">The previous challenges loaded from Local Storage.</param>
        /// <returns></returns>
        public async Task RetrieveChallenges(List<Challenge> savedChallenges)
        {
            List<Challenge> newChallenges = new List<Challenge>();

            WebClient webClient = new WebClient();

            string challengeTxt = await webClient.RetrieveDocURL(_challengeURL);

            string[] challengeSplit = challengeTxt.Split('\n');

            Challenge currentParsingChallenge = null;
            foreach (string line in challengeSplit)
            {
                int possibleId = 0;
                if (Int32.TryParse(line, out possibleId)) //Try seeing if a new ID challenge was hit.
                {
                    if (currentParsingChallenge != null)
                    {
                        bool add = true;
                        foreach (Challenge savedChallenge in savedChallenges)
                        {
                            if (currentParsingChallenge.Title == savedChallenge.Title)
                            {
                                add = false; //Don't add this to the List of challenges, it has been already saved.
                                newChallenges.Add(savedChallenge);
                            }
                        }
                        if (add)
                        {
                            newChallenges.Add(currentParsingChallenge);
                        }
                    }
                    currentParsingChallenge = new Challenge();
                }
                else
                {
                    if (!(currentParsingChallenge == null))
                    {
                        switch (line.Split(':')[0]) //Switch between each different  possible challenge identifier.
                        {
                            case "T":
                                currentParsingChallenge.Title = line.Split(':')[1];
                                break;
                            case "D":
                                currentParsingChallenge.Description = line.Split(':')[1];
                                break;
                            case "R":
                                currentParsingChallenge.Rating = Int32.Parse(line.Split(':')[1]);
                                break;
                            case "SI":
                                currentParsingChallenge.SampleInput = line.Split(':')[1];
                                break;
                            case "SO":
                                currentParsingChallenge.SampleOutput = line.Split(':')[1];
                                break;
                            case "I":
                                currentParsingChallenge.TestInput = line.Split(':')[1];
                                break;
                            case "O":
                                currentParsingChallenge.TestOutput = line.Split(':')[1];
                                break;
                        }
                    }
                }
            }

            ChallengeList = newChallenges;
        }

        /// <summary>
        /// Generates the UI Positioning in the GridView.
        /// Recommended: 175px Height, 200px Width, 3 objects max, 6 max objects.
        /// </summary>
        public void GeneratePositionChallenges(int rowWidth, int columnWidth, int maxObjectsColumnRow, int amountObjects)
        {
            MiniChallengeList = new List<Challenge>();
            for (int i = 0; i < amountObjects; i++)
            {
                Challenge generatedChallenge = new Challenge();
                bool found = false;
                while (!found)
                {
                    generatedChallenge = ChallengeList[new Random().Next(ChallengeList.Count)];
                    //Makes sure a challenge found isn't repeated.
                    if (!MiniChallengeList.Contains(generatedChallenge))
                    {
                        found = true;
                    }
                    else
                    {
                        if (MiniChallengeList.Count >= ChallengeList.Count) //There are not enough Challenges to populate the MiniChallengeList.
                        {
                            break;
                        }
                    }
                }

                //First object is the largest.
                if (i == 0)
                {
                    generatedChallenge.ColSpan = 2;
                    generatedChallenge.RowSpan = 2;
                }
                else if (i == 7)
                {
                    generatedChallenge.ColSpan = 1;
                    generatedChallenge.RowSpan = 2;
                }
                else
                {
                    generatedChallenge.ColSpan = 1;
                    generatedChallenge.RowSpan = 1;
                }

                generatedChallenge.TemplateWidth = generatedChallenge.ColSpan * rowWidth;
                generatedChallenge.TemplateHeight = generatedChallenge.RowSpan * columnWidth;

                generatedChallenge.Color = GetRandomColor();

                MiniChallengeList.Add(generatedChallenge);

            }
        }


        public SolidColorBrush GetRandomColor()
        {
            switch (new Random().Next(5))
            {
                case 0:
                    return new SolidColorBrush(Windows.UI.Color.FromArgb(255, 0, 176, 153)); //Blue
                case 1:
                    return new SolidColorBrush(Windows.UI.Color.FromArgb(255, 0, 120, 0)); //Dark Green
                case 2:
                    return new SolidColorBrush(Windows.UI.Color.FromArgb(255, 208, 119, 0)); //Orange
                case 3:
                    return new SolidColorBrush(Windows.UI.Color.FromArgb(255, 146, 86, 255)); //Purple
                case 4:
                    return new SolidColorBrush(Windows.UI.Color.FromArgb(255, 0, 69, 64)); //Dark Blue
            }

            return new SolidColorBrush(Windows.UI.Color.FromArgb(2, 2, 2, 2));
        }





    }
}
